package com.hwg.shiliupro.controller;

import com.hwg.shiliupro.dto.LoginDto;
import com.hwg.shiliupro.finals.Code;
import com.hwg.shiliupro.po.*;
import com.hwg.shiliupro.service.PermissionService;
import com.hwg.shiliupro.service.RolePermissionService;
import com.hwg.shiliupro.service.UserRoleService;
import com.hwg.shiliupro.service.UserService;
import com.hwg.shiliupro.utils.AuthorityUtils;
import com.hwg.shiliupro.utils.CheckCodeUtil;
import com.hwg.shiliupro.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/api/login")
public class LoginController {
    @Autowired
    private UserService userService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RolePermissionService rolePermissionService;
    @Autowired
    private PermissionService permissionService;

    /**
     * 登录的控制器方法
     * @param loginDto 登录dto
     * @return {@link R}
     */
    @PostMapping
    public R login(@RequestBody LoginDto loginDto,HttpServletRequest request){
        log.info("登录接收到的dto为：{}",loginDto);
        //校验验证码
        HttpSession session = request.getSession();
        String sessionCheckCode = (String) session.getAttribute("checkCode");
        String checkCode = loginDto.getCheckCode();
        if(!sessionCheckCode.equalsIgnoreCase(checkCode)){
            return R.error().code(Code.GET_ERR).message("验证码错误~");
        }
        //校验验证码通过
        User user = userService.login(loginDto);
        if(user != null){
            //判断是否进入黑名单
            User block = userService.isBlock(user.getId());
            if(block != null){
                //说明进入了黑名单
                return R.error().code(Code.GET_ERR).message("您暂时进入了黑名单");
            }
            //查询成功  登录成功
            log.info("登陆成功的用户信息：{}",user);
            session.setAttribute("userName",user.getName());
            //1、生成并返回Token  (并把用户信息存储在Token)
            String jwtToken = JwtUtils.getJwtToken(user.getId().toString(), user);
            log.info("生成的token为：{}",jwtToken);
            //2、为用户生成权限
//            AuthorityUtils.clear();   这个不能写
            //2.1通过用户id查询到角色id   由于是多对多 一个用户id可能对应多个角色 因此应该用集合
            List<UserRole> userRoles = userRoleService.selectRoleByUid(user.getId());
            List<Integer> rIds = new ArrayList<>();
            for (UserRole userRole : userRoles) {
                rIds.add(userRole.getRId());
            }
            log.info("根据用户uId查询到的用户--角色表信息：{}",userRoles);
            //2.2通过角色id(可能多个角色)   把查出来的权限  一一加入
            List<String> permissionList = new ArrayList<>();
            for (Integer rId : rIds) {
                //遍历多个角色id 得到角色--权限表信息  1个角色有多个权限
                List<RolePermission> rolePermissions = rolePermissionService.selectPermissionsByRid(rId);
                log.info("根据角色rId查询到的角色--权限表信息：{}",rolePermissions);
                for (RolePermission rolePermission : rolePermissions) {
                    //遍历权限集合,通过权限的id去查询权限表 将权限标识添加至AuthorityUtils的成员变量中去
                    Permission permission = permissionService.selectPermission(rolePermission.getPId());
                    permissionList.add(permission.getFlag());
                }
            }
            log.info("两次循环后得到的权限表：{}",permissionList);
            //将权限标识添加至AuthorityUtils的成员变量中去
            AuthorityUtils.setAuthorities(user.getId().toString(),permissionList);
            HashMap<String,Object> map = new HashMap<>();
            map.put("token",jwtToken);
            map.put("rIds",rIds);
            map.put("userName",user.getName());
            map.put("uId",user.getId());
            //WebSocket
//            WebSocket.loginUserPool.put(user.getName(),user);
            return R.ok().code(Code.GET_OK).data(map);
        }
        return R.error().code(Code.GET_ERR).message("学号/密码错误");
    }

    /**
     * 验证码控制器方法
     *
     * @param request  请求
     * @param response 响应
     */
    @GetMapping("/checkCode")
    public void checkCode(HttpServletRequest request, HttpServletResponse response){
        try {
            HttpSession session = request.getSession();
//            log.info("生成验证码的会话session是：{}",session);
            //生成验证码
            ServletOutputStream os = response.getOutputStream();    //response的字节输出流
            String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, os, 4);
            //checkCode方法生成的验证码  验证码的数据要存入到Session (两次请求之间数据共享 )
            // 逻辑： 一存一取 一比对
            session.setAttribute("checkCode",checkCode);
            log.info("后台生成的验证码:{}",checkCode);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
